package com.iplant.aps.serviceImpl.utils.aps;

import com.iplant.aps.service.apsenum.aps.APSShiftPeriod;
import com.iplant.aps.service.apsenum.aps.APSTaskStatus;
import com.iplant.aps.service.po.aps.APSManuCapacity;
import com.iplant.aps.service.po.aps.APSTaskPart;
import com.iplant.aps.service.po.aps.APSTaskPartPoint;
import com.iplant.base.utils.serializer.CloneTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.basic.service.po.cfg.CFGCalendar;
import com.iplant.basic.service.po.fmc.FMCTimeZone;
import com.iplant.pdm.service.po.bop.FPCRoutePartPoint;

import java.util.*;
import java.util.stream.Collectors;

public class FPCRoutePartPointUtils {

    private List<FPCRoutePartPoint> APSRoutePartList = new ArrayList<FPCRoutePartPoint>();

    private Map<Integer, FPCRoutePartPoint> FPCRoutePartPointMap = new HashMap<>();

    public FPCRoutePartPointUtils(List<FPCRoutePartPoint> wRoutePartList) {
        APSRoutePartList = wRoutePartList;
        PrevRoutePartMap = APSRoutePartList.stream().collect(Collectors.groupingBy(p -> p.PrevPartPointID));
        FPCRoutePartPointMap = APSRoutePartList.stream().collect(Collectors.toMap(p -> p.ID, p -> p, (o1, o2) -> o2));
    }

    private List<List<FPCRoutePartPoint>> PartOrderRouteList = new ArrayList<List<FPCRoutePartPoint>>();

    private Map<Integer, List<FPCRoutePartPoint>> PrevRoutePartMap = new HashMap<Integer, List<FPCRoutePartPoint>>();

    /**
     * 获取工位工艺路线扁平表
     */
    public List<List<FPCRoutePartPoint>> GetPartOrderRouteList() {
        if (PartOrderRouteList == null)
            PartOrderRouteList = new ArrayList<List<FPCRoutePartPoint>>();
        PartOrderRouteList.clear();

        List<FPCRoutePartPoint> wStartList = APSRoutePartList.stream().filter(p -> p.PrevPartPointID <= 0)
                .collect(Collectors.toList());

        List<FPCRoutePartPoint> wMainList = null;
        for (FPCRoutePartPoint wFPCRoutePartPoint : wStartList) {
            wMainList = new ArrayList<FPCRoutePartPoint>();
            SetRoutePartStationList(wMainList, wFPCRoutePartPoint);
            this.AddResult(PartOrderRouteList, wMainList);
        }
        APSRoutePartList.sort(Comparator.comparing(FPCRoutePartPoint::getOrderID).thenComparing(q -> q.PrevPartPointID));

        for (FPCRoutePartPoint wFPCRoutePartPoint : APSRoutePartList) {
            if (wFPCRoutePartPoint.NextPartPointID != null && wFPCRoutePartPoint.NextPartPointID.size() > 0) {

                List<FPCRoutePartPoint> wTempList = null;
                for (Integer wPartID : wFPCRoutePartPoint.NextPartPointID) {
                    if (!FPCRoutePartPointMap.containsKey(wPartID))
                        continue;
                    ;
                    if (CheckRouteExist(wFPCRoutePartPoint.ID, wPartID))
                        continue;

                    List<List<FPCRoutePartPoint>> wNextPartIDSuffList = GetPartRouteSuffList(wPartID);

                    if (RouteListTemp.size() == 0) {
                        // 首工位 在已算出的工艺路径中不存在 wFPCRoutePartPoint.PartID->wPartID
                        // wFPCRoutePartPoint.PartID 是开始工位
                        continue;
                    } else {
                        for (List<FPCRoutePartPoint> wPrefix : RouteListTemp) {

                            if (wNextPartIDSuffList.size() == 0) {
                                // 无任何路径包含此工位 配置不合理可以
                                wTempList = CloneTool.CloneArray(wPrefix, FPCRoutePartPoint.class);
                                wTempList.add(wFPCRoutePartPoint);
                                wTempList.add(FPCRoutePartPointMap.get(wPartID));
                                this.AddResult(PartOrderRouteList, wTempList);
                            } else {
                                for (List<FPCRoutePartPoint> wSuff : wNextPartIDSuffList) {
                                    wTempList = CloneTool.CloneArray(wPrefix, FPCRoutePartPoint.class);
                                    wTempList.add(wFPCRoutePartPoint);
                                    wTempList.add(FPCRoutePartPointMap.get(wPartID));
                                    wTempList.addAll(wSuff);
                                    this.AddResult(PartOrderRouteList, wTempList);
                                }
                            }
                        }
                    }
                }
            }
        }
        // 去重
        int wSize = PartOrderRouteList.size();
        if (wSize > 1) {

            for (int i = 0; i < wSize; i++) {
                if (i >= PartOrderRouteList.size())
                    break;
                if (PartOrderRouteList.get(i) == null || PartOrderRouteList.get(i).size() == 0
                        || IsExit(PartOrderRouteList, i)) {
                    PartOrderRouteList.remove(i);
                    i--;
                }
            }
        }
        return PartOrderRouteList;
    }

    /**
     * 根据已排计划 获得未做的工位工艺路径列表
     */
    public static List<List<FPCRoutePartPoint>> GetUndoStationRouteList(BMSEmployee wLoginUser,
                                                                        List<APSTaskPart> wDoneStationList,
																		Map<Integer, APSManuCapacity> wManuCapacityMap,
                                                                        List<List<FPCRoutePartPoint>> wRoutePartIntegerList, int wWrokDay, Map<Integer, APSTaskPart> wUndoOrUnStartTaskList,
                                                                        List<FMCTimeZone> wAllZoneList, Map<Integer,
			List<CFGCalendar>> wCalendarMap) {
        List<List<FPCRoutePartPoint>> wResult = new ArrayList<List<FPCRoutePartPoint>>();

        wDoneStationList = wDoneStationList.stream()
                .sorted(Comparator.comparing(APSTaskPart::getShiftPeriod)
                        .thenComparing((o1, o2) -> o2.PartStartTime.compareTo(o1.PartStartTime)) // 班次倒序
                        .thenComparing((o1, o2) -> o1.EditTime.compareTo(o2.EditTime)))
                .collect(Collectors.toList());

        // 将订单任务排序 让周计划排前面 且根据班次排列 然后根据提交时间排列
        APSManuCapacity wManuCapacity = null;
        // 确切做完的工位任务
        Map<Integer, List<APSTaskPart>> wMap = wDoneStationList.stream()
                .filter(p -> p.Active == 1
                        && (p.Status == APSTaskStatus.Done.getValue() || p.Status == APSTaskStatus.Aborted.getValue()))
                .collect(Collectors.groupingBy(p -> p.RoutePartID));

        // 循环将周计划中预计完成的任务剔除出未完成任务
        // 然后根据周计划最大结束时间与月计划比对
        // 月计划在此时间之后的计划预计能完成 将此任务剔除出未完成任务
        APSTaskPart wCreateTaskPart = new APSTaskPart();
        // Load DB
        for (APSTaskPart wAPSTaskPart : wDoneStationList) {
            if (wAPSTaskPart.Active != 1 || (wAPSTaskPart.Status != APSTaskStatus.Issued.getValue()
                    && wAPSTaskPart.Status != APSTaskStatus.Started.getValue()))
                continue;

            if (wMap.containsKey(wAPSTaskPart.RoutePartID))
                continue;

            if (!wManuCapacityMap.containsKey(wAPSTaskPart.RoutePartID))
                continue;

            wManuCapacity = wManuCapacityMap.get(wAPSTaskPart.RoutePartID);

            if (wCreateTaskPart.RoutePartID != wAPSTaskPart.RoutePartID) {
                if (wUndoOrUnStartTaskList.containsKey(wAPSTaskPart.RoutePartID)) {

                    wCreateTaskPart = wUndoOrUnStartTaskList.get(wAPSTaskPart.RoutePartID);

                    if (wCreateTaskPart.PartEndTime.compareTo(wAPSTaskPart.PartEndTime) < 0) {

                        wCreateTaskPart.setPartEndTime(wAPSTaskPart.PartEndTime);
                    }

                } else {
                    wCreateTaskPart = new APSTaskPart();
                    wCreateTaskPart.setRoutePartID(wAPSTaskPart.RoutePartID);
                    wCreateTaskPart.setActive(1);

                    wCreateTaskPart.setWorkShopName(wAPSTaskPart.WorkShopName);
                    wCreateTaskPart.setLineID(wAPSTaskPart.LineID);
                    wCreateTaskPart.setOrderID(wAPSTaskPart.OrderID);

                    wCreateTaskPart.setPartEndTime(wAPSTaskPart.PartEndTime);
                    wUndoOrUnStartTaskList.put(wAPSTaskPart.RoutePartID, wCreateTaskPart);
                }
            }
            if (wAPSTaskPart.ShiftPeriod == APSShiftPeriod.Week.getValue()) {
                long work = 0;
//				APSWorkTimeCalcUtilsBack.getInstance().CalcIntervalTime(wLoginUser, wCreateTaskPart.PartID,
//						wWrokDay, wAPSTaskPart.StartTime, wAPSTaskPart.EndTime, wAllZoneList, wCalendarMap);

//				if (((wCreateTaskPart.WorkHour * 60) + work) > (wManuCapacity.WorkHour * 60)) {
//					if (!wMap.containsKey(wCreateTaskPart.PartID)) {
//						wMap.put(wCreateTaskPart.PartID, StringUtils.parseList(new APSTaskPart[] { wAPSTaskPart }));
//					}
//					if (wUndoOrUnStartTaskList.containsKey(wCreateTaskPart.PartID))
//						wUndoOrUnStartTaskList.remove(wCreateTaskPart.PartID);
//				}

            } else if (wAPSTaskPart.ShiftPeriod == APSShiftPeriod.Month.getValue()) {
                if (wAPSTaskPart.PartEndTime.compareTo(wCreateTaskPart.PartEndTime) > 0) {
                    long work = 0;
                    if (wAPSTaskPart.PartStartTime.compareTo(wCreateTaskPart.PartEndTime) > 0) {
//						work = APSWorkTimeCalcUtilsBack.getInstance().CalcIntervalTime(wLoginUser,
//								wCreateTaskPart.PartID, wWrokDay, wAPSTaskPart.StartTime, wAPSTaskPart.EndTime,
//								wAllZoneList, wCalendarMap);
                    } else {
//						work = APSWorkTimeCalcUtilsBack.getInstance().CalcIntervalTime(wLoginUser,
//								wCreateTaskPart.PartID, wWrokDay, wCreateTaskPart.EndTime, wAPSTaskPart.EndTime,
//								wAllZoneList, wCalendarMap);
                    }
//					if (((wCreateTaskPart.WorkHour * 60) + work) > (wManuCapacity.WorkHour * 60)) {
//						if (!wMap.containsKey(wCreateTaskPart.PartID)) {
//							wMap.put(wCreateTaskPart.PartID, StringUtils.parseList(new APSTaskPart[] { wAPSTaskPart
//							}));
//						}
//						if (wUndoOrUnStartTaskList.containsKey(wCreateTaskPart.PartID))
//							wUndoOrUnStartTaskList.remove(wCreateTaskPart.PartID);
//					}
                }
            }

        }

        // 预计做完的工位任务

        for (List<FPCRoutePartPoint> list : wRoutePartIntegerList) {

            for (int i = 0; i < list.size(); i++) {
                if (wMap.containsKey(list.get(i))) {
                    continue;
                }
                wResult.add(StringUtils.parseList(Arrays.copyOfRange(list.toArray(new FPCRoutePartPoint[0]), i,
						list.size())));
                break;
            }
        }
        // 去重
        int wSize = wResult.size();
        if (wSize > 1) {

            for (int i = 0; i < wSize; i++) {
                if (i >= wResult.size())
                    break;
                if (wResult.get(i) == null || wResult.get(i).size() == 0 || IsExit(wResult, i)) {
                    wResult.remove(i);
                    i--;
                }
            }
        }

        return wResult;
    }

    /**
     * 根据已排计划 获得未排程的工位工艺路径列表
     */
    public static List<List<FPCRoutePartPoint>> GetUndoStationRouteList(BMSEmployee wLoginUser,
                                                                        List<APSTaskPartPoint> wDoneStationList,
																		List<List<FPCRoutePartPoint>> wRoutePartIntegerList) {
        List<List<FPCRoutePartPoint>> wResult = new ArrayList<List<FPCRoutePartPoint>>();
        try {


            Map<Integer, List<APSTaskPartPoint>> wMap = wDoneStationList.stream()
                    .filter(p -> p.Active == 1 && (p.Status == APSTaskStatus.Confirm.getValue()
                            || p.Status == APSTaskStatus.Started.getValue()
                            || p.Status == APSTaskStatus.Suspend.getValue() || p.Status == APSTaskStatus.Done.getValue()
                            || p.Status == APSTaskStatus.Aborted.getValue()))
                    .collect(Collectors.groupingBy(p -> p.RoutePartPointID));

            int wRepeatIndex = -1;
            // 循环工艺路线判断哪个任务没有任务

            for (List<FPCRoutePartPoint> list : wRoutePartIntegerList) {

                wRepeatIndex = -1;
                for (int i = 0; i < list.size(); i++) {
                    if (wMap.containsKey(list.get(i))) {
                        wRepeatIndex = i;
                    }
                }

                wResult.add(StringUtils
                        .parseList(Arrays.copyOfRange(list.toArray(new FPCRoutePartPoint[0]), wRepeatIndex + 1,
								list.size())));
            }
            // 去重
            int wSize = wResult.size();
            if (wSize > 1) {

                for (int i = 0; i < wSize; i++) {
                    if (i >= wResult.size())
                        break;
                    if (wResult.get(i) == null || wResult.get(i).size() == 0 || IsExit(wResult, i)) {
                        wResult.remove(i);
                        i--;
                    }
                }
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
        }

        return wResult;
    }

    private List<List<FPCRoutePartPoint>> RouteListTemp = new ArrayList<>();

    private boolean AddResult(List<List<FPCRoutePartPoint>> wPartOrderRouteList, List<FPCRoutePartPoint> wTempList) {
        if (IsExit(wPartOrderRouteList, wTempList)) {
            return false;
        }
//		System.out.println(wTempList);
        return wPartOrderRouteList.add(wTempList);
    }

    private boolean CheckRouteExist(Integer wPartID, Integer wNextPartID) {
        List<FPCRoutePartPoint> wRouteTemp = null;
        RouteListTemp.clear();
        for (List<FPCRoutePartPoint> wRoute : PartOrderRouteList) {

            if (wRoute == null || wRoute.size() == 0)
                continue;

            wRouteTemp = new ArrayList<FPCRoutePartPoint>();
            for (int i = 0; i < wRoute.size(); i++) {

                if (wRoute.get(i).ID == wPartID) {
                    wRouteTemp = StringUtils.parseList(Arrays.copyOfRange(wRoute.toArray(new FPCRoutePartPoint[0]), 0
							, i));

                    if (wRoute.size() > (i - 2) && wRoute.get(i).ID == wNextPartID) {
                        return true;
                    }
                }

            }
            if (wRouteTemp.size() > 0)
                RouteListTemp.add(wRouteTemp);

        }

        // 去重
        int wSize = RouteListTemp.size();
        if (wSize > 1) {

            for (int i = 0; i < wSize; i++) {
                if (i >= RouteListTemp.size())
                    break;
                if (RouteListTemp.get(i) == null || RouteListTemp.get(i).size() == 0 || IsExit(RouteListTemp, i)) {
                    RouteListTemp.remove(i);
                    i--;
                    wSize--;
                }
            }
        }
        return false;
    }

    private static boolean IsExit(List<List<FPCRoutePartPoint>> wAllList, int wIndex) {
        for (int i = 0; i < wAllList.size(); i++) {
            if (i == wIndex)
                continue;
            if (IsSameAs(wAllList.get(i), wAllList.get(wIndex)))
                return true;
        }
        return false;
    }

    private static boolean IsExit(List<List<FPCRoutePartPoint>> wAllList, List<FPCRoutePartPoint> wTempList) {
        for (int i = 0; i < wAllList.size(); i++) {

            if (IsSameAs(wAllList.get(i), wTempList))
                return true;
        }
        return false;
    }

    private static boolean IsSameAs(List<FPCRoutePartPoint> wList1, List<FPCRoutePartPoint> wList2) {

        if (wList1 != null && wList2 != null && wList1.size() >= wList2.size()) {
            for (int i = 0; i < wList2.size(); i++) {
                if (wList1.get(i).ID != wList2.get(i).ID) {
                    return false;
                }
            }
            return true;
        }

        return false;
    }

    private List<List<FPCRoutePartPoint>> GetPartRouteSuffList(int wPartID) {
        List<List<FPCRoutePartPoint>> wResult = new ArrayList<List<FPCRoutePartPoint>>();

        List<FPCRoutePartPoint> wRouteTemp = null;
        for (List<FPCRoutePartPoint> wRoute : PartOrderRouteList) {

            if (wRoute == null || wRoute.size() == 0)
                continue;
            wRouteTemp = new ArrayList<>();
            for (int i = 0; i < wRoute.size(); i++) {

                if (wRoute.get(i).ID != wPartID)

                    continue;
                if (i == wRoute.size() - 1)
                    continue;

                wRouteTemp = StringUtils
                        .parseList(Arrays.copyOfRange(wRoute.toArray(new FPCRoutePartPoint[0]), i + 1, wRoute.size()));
            }
            if (wRouteTemp.size() > 0)
                wResult.add(wRouteTemp);
        }
        // 去重
        int wSize = wResult.size();
        if (wSize > 1) {

            for (int i = 0; i < wSize; i++) {
                if (i >= wResult.size())
                    break;
                if (wResult.get(i) == null || wResult.get(i).size() == 0 || IsExit(wResult, i)) {
                    wResult.remove(i);
                    i--;
                    wSize--;
                }
            }
        }
        return wResult;
    }

    /**
     * 根据PrevID生成工位顺序
     */
    private void SetRoutePartStationList(List<FPCRoutePartPoint> wStationList, FPCRoutePartPoint wStationID) {

        wStationList.add(wStationID);
        if (PrevRoutePartMap.containsKey(wStationID.ID)) {
            List<FPCRoutePartPoint> wFPCRoutePartPointList = PrevRoutePartMap.get(wStationID.ID);
            if (wFPCRoutePartPointList != null && wFPCRoutePartPointList.size() > 0) {

                List<FPCRoutePartPoint> wClone = CloneTool.CloneArray(wStationList, FPCRoutePartPoint.class);
                List<FPCRoutePartPoint> wClone_S = new ArrayList<FPCRoutePartPoint>();
                for (int i = 0; i < wFPCRoutePartPointList.size(); i++) {
                    if (i > 0) {
                        if (wStationList.contains(wFPCRoutePartPointList.get(i)))
                            continue;

                        wClone_S = CloneTool.CloneArray(wClone, FPCRoutePartPoint.class);
                        SetRoutePartStationList(wClone_S, wFPCRoutePartPointList.get(i));
                        this.AddResult(PartOrderRouteList, wClone_S);

                    } else {
                        SetRoutePartStationList(wStationList, wFPCRoutePartPointList.get(i));
                    }

                }
            }

        }

    }

}
